﻿using System;
using System.Collections.Generic;
using Extend.Event;

namespace Extend.Event
{
    public delegate void Callback();
    public delegate void Callback<T>(T arg1);
    public delegate void Callback<T, U>(T arg1, U arg2);
    public delegate void Callback<T, U, V>(T arg1, U arg2, V arg3);
    public delegate void Callback<T, U, V, W>(T arg1, U arg2, V arg3, W arg4);
    public delegate void Callback<T, U, V, W, X>(T arg1, U arg2, V arg3, W arg4, X arg5);

    public delegate void Callback_NetMessage_Handle(object _data);

    internal class MsgAction
    {
        string msg;
        Action action;
        public void Init(string msg, Action action)
        {
            this.msg = msg;
            this.action = action;
        }

        public void Excute()
        {
            try
            {
                if (action != null) action();
            }
            catch (Exception e)
            {
                UnityEngine.Debug.LogErrorFormat("Msg:{0},Error:{1}", msg, e.ToString());
            }
        }

        public void Release()
        {
            msg = string.Empty;
            action = null;
        }

    }
}

/// <summary>
/// 静态全局消息分发执行管理器
/// </summary>
public static class MessageCenter
{
    #region 普通消息
    //普通消息
    private static Dictionary<string, List<Delegate>> MsgList = new Dictionary<string, List<Delegate>>();

    /// <summary>
    /// 回调执行队列
    /// </summary>
    private static Queue<MsgAction> callbackQueue = new Queue<MsgAction>();

    /// <summary>
    /// 消息回调池
    /// </summary>
    private static UnityObjectPool<MsgAction> MsgActionPool = new UnityObjectPool<MsgAction>(null, (msgAction) => { msgAction.Release(); });


    private static object lockObject = new object();

    /// <summary>
    /// 移除监听
    /// </summary>
    /// <param name="msgName"></param>
    /// <param name="callBack"></param>
    private static void _AddListener(string msgName, Delegate callBack)
    {
        lock (lockObject)
        {
            if (MsgList.ContainsKey(msgName))
            {
                List<Delegate> dList = MsgList[msgName];

                for (int i = 0; i < dList.Count; ++i)
                {
                    if (callBack == dList[i])
                    {
                        return;
                    }
                }

                dList.Add(callBack);
                //else if (BaseLogger.isDebug) BaseLogger.WarningFormat("当前消息{0}类型有误！", msgName);
            }
            else
            {
                List<Delegate> list = new List<Delegate>();
                list.Add(callBack as Delegate);
                MsgList.Add(msgName, list);
            }
        }

    }

    /// <summary>
    /// 添加监听
    /// </summary>
    /// <param name="msgName"></param>
    /// <param name="callBack"></param>
    private static void _RemoveListener(string msgName, Delegate callBack)
    {
        lock (lockObject)
        {
            if (MsgList.ContainsKey(msgName))
            {
                MsgList[msgName].Remove(callBack);
            }
        }

    }

    private static void Error(string msgName, Delegate callBack)
    {
        UnityEngine.Debug.LogErrorFormat("事件发送参数与接收方法不匹配=>MsgName:{0},TargetName:{1},MethodName:{2}", msgName, callBack.Target, callBack.Method.Name);
    }

    /// <summary>
    /// 添加普通消息监听者
    /// </summary>
    /// <param name="msgName"></param>
    /// <param name="_callback"></param>
    public static void AddListener(string msgName, Callback _callback)
    {
        _AddListener(msgName, _callback);
    }
    public static void AddListener<T>(string msgName, Callback<T> _callback)
    {
        _AddListener(msgName, _callback);
    }
    public static void AddListener<T, U>(string msgName, Callback<T, U> _callback)
    {
        _AddListener(msgName, _callback);
    }
    public static void AddListener<T, U, V>(string msgName, Callback<T, U, V> _callback)
    {
        _AddListener(msgName, _callback);
    }
    public static void AddListener<T, U, V, W>(string msgName, Callback<T, U, V, W> _callback)
    {
        _AddListener(msgName, _callback);
    }
    public static void AddListener<T, U, V, W, X>(string msgName, Callback<T, U, V, W, X> _callback)
    {
        _AddListener(msgName, _callback);
    }

    /// <summary>
    /// 删除普通消息监听者
    /// </summary>
    /// <param name="msgName"></param>
    /// <param name="_callback"></param>
    public static void RemoveListener(string msgName, Callback _callback)
    {
        _RemoveListener(msgName, _callback);
    }
    public static void RemoveListener<T>(string msgName, Callback<T> _callback)
    {
        _RemoveListener(msgName, _callback);
    }
    public static void RemoveListener<T, U>(string msgName, Callback<T, U> _callback)
    {
        _RemoveListener(msgName, _callback);
    }
    public static void RemoveListener<T, U, V>(string msgName, Callback<T, U, V> _callback)
    {
        _RemoveListener(msgName, _callback);
    }
    public static void RemoveListener<T, U, V, W>(string msgName, Callback<T, U, V, W> _callback)
    {
        _RemoveListener(msgName, _callback);
    }
    public static void RemoveListener<T, U, V, W, X>(string msgName, Callback<T, U, V, W, X> _callback)
    {
        _RemoveListener(msgName, _callback);
    }

    /// <summary>
    /// 发送消息
    /// 且马上执行监听事件
    /// </summary>
    /// <param name="msgName"></param>
    public static void SendMessage(string msgName)
    {
        lock (lockObject)
        {
            if (MsgList.ContainsKey(msgName))
            {
                List<Delegate> list = MsgList[msgName];
                if (list.Count == 0)
                    return;
                for (int i = list.Count -1; i >= 0; i--)
                {
                    if (list[i] is Callback)
                    {
                        (list[i] as Callback).Invoke();
                    }
                    else
                    {
                        Error(msgName, list[i]);
                    }
                }
            }
        }
    }
    public static void SendMessage<T>(string msgName, T arg1)
    {
        lock (lockObject)
        {
            if (MsgList.ContainsKey(msgName))
            {
                List<Delegate> list = MsgList[msgName];
                if (list.Count == 0)
                    return;
                for (int i = list.Count - 1; i >= 0; i--)
                {
                    if (list[i] is Callback<T>)
                    {
                        (list[i] as Callback<T>).Invoke(arg1);
                    }
                    else
                    {
                        Error(msgName, list[i]);
                    }
                }
            }
        }

    }
    public static void SendMessage<T, U>(string msgName, T arg1, U arg2)
    {
        lock (lockObject)
        {
            if (MsgList.ContainsKey(msgName))
            {
                List<Delegate> list = MsgList[msgName];
                if (list.Count == 0)
                    return;
                for (int i = list.Count - 1; i >= 0; i--)
                {
                    if (list[i] is Callback<T, U>)
                    {
                        (list[i] as Callback<T, U>).Invoke(arg1, arg2);
                    }
                    else
                    {
                        Error(msgName, list[i]);
                    }
                }
            }
        }
    }
    public static void SendMessage<T, U, V>(string msgName, T arg1, U arg2, V arg3)
    {
        lock (lockObject)
        {
            if (MsgList.ContainsKey(msgName))
            {
                List<Delegate> list = MsgList[msgName];
                if (list.Count == 0)
                    return;
                for (int i = list.Count - 1; i >= 0; i--)
                {
                    if (list[i] is Callback<T, U, V>)
                    {
                        (list[i] as Callback<T, U, V>).Invoke(arg1, arg2, arg3);
                    }
                    else
                    {
                        Error(msgName, list[i]);
                    }
                }
            }
        }
    }
    public static void SendMessage<T, U, V, W>(string msgName, T arg1, U arg2, V arg3, W arg4)
    {
        lock (lockObject)
        {
            if (MsgList.ContainsKey(msgName))
            {
                List<Delegate> list = MsgList[msgName];
                if (list.Count == 0)
                    return;
                for (int i = list.Count - 1; i >= 0; i--)
                {
                    if (list[i] is Callback<T, U, V, W>)
                    {
                        (list[i] as Callback<T, U, V, W>).Invoke(arg1, arg2, arg3, arg4);
                    }
                    else
                    {
                        Error(msgName, list[i]);
                    }
                }
            }
        }
    }
    public static void SendMessage<T, U, V, W, X>(string msgName, T arg1, U arg2, V arg3, W arg4, X arg5)
    {
        lock (lockObject)
        {
            if (MsgList.ContainsKey(msgName))
            {
                List<Delegate> list = MsgList[msgName];
                if (list.Count == 0)
                    return;
                for (int i = list.Count - 1; i >= 0; i--)
                {
                    if (list[i] is Callback<T, U, V, W, X>)
                    {
                        (list[i] as Callback<T, U, V, W, X>).Invoke(arg1, arg2, arg3, arg4, arg5);
                    }
                    else
                    {
                        Error(msgName, list[i]);
                    }
                }
            }
        }
    }

    /// <summary>
    /// 广播普通消息
    /// 使用了回调，无法马上执行到监听事件
    /// </summary>
    /// <param name="msgName"></param>
    private static void Brocast(string msgName)
    {
        lock (lockObject)
        {
            if (MsgList.ContainsKey(msgName))
            {
                List<Delegate> list = MsgList[msgName];
                if (list.Count == 0)
                    return;
                Action action = () =>
                {
                    for (int i = 0; i < list.Count; i++)
                    {
                        if (list[i] is Callback)
                        {
                            (list[i] as Callback).Invoke();
                        }
                        else
                        {
                            Error(msgName, list[i]);
                        }
                    }
                };
                AddCallBack(action, msgName);
            }
        }
    }
    private static void Brocast<T>(string msgName, T arg1)
    {
        lock (lockObject)
        {
            if (MsgList.ContainsKey(msgName))
            {
                List<Delegate> list = MsgList[msgName];
                if (list.Count == 0)
                    return;
                Action action = () =>
                {
                    for (int i = 0; i < list.Count; i++)
                    {
                        if (list[i] is Callback<T>)
                        {
                            (list[i] as Callback<T>).Invoke(arg1);
                        }
                        else
                        {
                            Error(msgName, list[i]);
                        }
                    }
                };
                AddCallBack(action, msgName);
            }
        }

    }
    private static void Brocast<T, U>(string msgName, T arg1, U arg2)
    {
        lock (lockObject)
        {
            if (MsgList.ContainsKey(msgName))
            {
                List<Delegate> list = MsgList[msgName];
                if (list.Count == 0)
                    return;
                Action action = () =>
                {
                    for (int i = 0; i < list.Count; i++)
                    {
                        if (list[i] is Callback<T, U>)
                        {
                            (list[i] as Callback<T, U>).Invoke(arg1, arg2);
                        }
                        else
                        {
                            Error(msgName, list[i]);
                        }
                    }
                };
                AddCallBack(action, msgName);
            }
        }
    }
    private static void Brocast<T, U, V>(string msgName, T arg1, U arg2, V arg3)
    {
        lock (lockObject)
        {
            if (MsgList.ContainsKey(msgName))
            {
                List<Delegate> list = MsgList[msgName];
                if (list.Count == 0)
                    return;
                Action action = () =>
                {
                    for (int i = 0; i < list.Count; i++)
                    {
                        if (list[i] is Callback<T, U, V>)
                        {
                            (list[i] as Callback<T, U, V>).Invoke(arg1, arg2, arg3);
                        }
                        else
                        {
                            Error(msgName, list[i]);
                        }
                    }
                };
                AddCallBack(action, msgName);
            }
        }
    }
    private static void Brocast<T, U, V, W>(string msgName, T arg1, U arg2, V arg3, W arg4)
    {
        lock (lockObject)
        {
            if (MsgList.ContainsKey(msgName))
            {
                List<Delegate> list = MsgList[msgName];
                if (list.Count == 0)
                    return;
                Action action = () =>
                {
                    for (int i = 0; i < list.Count; i++)
                    {
                        if (list[i] is Callback<T, U, V, W>)
                        {
                            (list[i] as Callback<T, U, V, W>).Invoke(arg1, arg2, arg3, arg4);
                        }
                        else
                        {
                            Error(msgName, list[i]);
                        }
                    }
                };
                AddCallBack(action, msgName);
            }
        }
    }
    private static void Brocast<T, U, V, W, X>(string msgName, T arg1, U arg2, V arg3, W arg4, X arg5)
    {
        lock (lockObject)
        {
            if (MsgList.ContainsKey(msgName))
            {
                List<Delegate> list = MsgList[msgName];
                if (list.Count == 0)
                    return;
                Action action = () =>
                {
                    for (int i = 0; i < list.Count; i++)
                    {
                        if (list[i] is Callback<T, U, V, W, X>)
                        {
                            (list[i] as Callback<T, U, V, W, X>).Invoke(arg1, arg2, arg3, arg4, arg5);
                        }
                        else
                        {
                            Error(msgName, list[i]);
                        }
                    }
                };
                AddCallBack(action, msgName);
            }
        }
    }

    /// <summary>
    /// 添加回调到回调队列
    /// </summary>
    private static void AddCallBack(Action action, string msgName = "")
    {
        MsgAction msgAction = MsgActionPool.Get();
        msgAction.Init(msgName, action);
        callbackQueue.Enqueue(msgAction);
    }

    /// <summary>
    /// 执行回调函数
    /// </summary>
    public static void ExecuteCallBack()
    {
        lock (lockObject)
        {
            while (callbackQueue.Count > 0)
            {
                MsgAction msgAction = callbackQueue.Dequeue();
                msgAction.Excute();
                MsgActionPool.Release(msgAction);
            }
        }
    }

    #endregion

    public static void Clear()
    {
        MsgList.Clear();
        callbackQueue.Clear();
    }
}
